﻿using System;
using System.Runtime.InteropServices;
using Heaven.Mathematics;
using Heaven.Graphics;

using Direct3D9 = SlimDX.Direct3D9;
using Slimdx = SlimDX;


namespace Heaven.SlimDX.Graphics
{
    /// <summary>
    /// Конвертация различных типов и перечислений
    /// </summary>
    internal class Converter
    {
        /// <summary>
        /// Конвертация данных из массива 
        /// произвольных структур в массив байтов
        /// </summary>
        /// <typeparam name="T">Структура</typeparam>
        /// <param name="data">Массив структур</param>
        /// <param name="start">Индекс в исходном массиве с которого начинать</param>
        /// <param name="count">Колическтво элементов для копирования</param>
        /// <returns>Массив байтов</returns>
        public static byte[] ToArray<T>(T[] data, int start, int count) where T : struct
        {            
            int size = Marshal.SizeOf(data[0]);
            byte[] result = new byte[size * count];
            for(int i = start; i < start + count; i++)
            {
                for(int j = 0; j < size; j++)
                {
                    result[(i - start) * size + j] = Marshal.ReadByte(data[i], j); 
                }
            }
            return result;
        }

        /// <summary>
        /// Конвертация Heaven.Mathematics.Matrix4 в SlimDX.Matrix 
        /// </summary>
        /// <param name="m">Матрица Heaven.Mathematics.Matrix4 для конвертации</param>
        /// <returns>SlimDX.Matrix матрица</returns>
        static public Slimdx.Matrix Convert(Matrix4 m)
        {
            Slimdx.Matrix matrix = new Slimdx.Matrix();
            matrix.M11 = (float)m.M11;
            matrix.M12 = (float)m.M12;
            matrix.M13 = (float)m.M13;
            matrix.M14 = (float)m.M14;
            matrix.M21 = (float)m.M21;
            matrix.M22 = (float)m.M22;
            matrix.M23 = (float)m.M23;
            matrix.M24 = (float)m.M24;
            matrix.M31 = (float)m.M31;
            matrix.M32 = (float)m.M32;
            matrix.M33 = (float)m.M33;
            matrix.M34 = (float)m.M34;
            matrix.M41 = (float)m.M41;
            matrix.M42 = (float)m.M42;
            matrix.M43 = (float)m.M43;
            matrix.M44 = (float)m.M44;

            return matrix;
        }

        /// <summary>
        /// Конвертация SlimDX.Matrix в Heaven.Mathematics.Matrix4 
        /// </summary>
        /// <param name="m">Матрица SlimDX.Matrix для конвертации</param>
        /// <returns>Heaven.Mathematics.Matrix4 матрица</returns>
        static public Matrix4 Convert(Slimdx.Matrix m)
        {
            return new Matrix4( m.M11, m.M12, m.M13, m.M14,
                                m.M21, m.M22, m.M23, m.M24,
                                m.M31, m.M32, m.M33, m.M34,
                                m.M41, m.M42, m.M43, m.M44);
        }

         /// <summary>
        /// Конвертация режима отсечения полигонов
        /// </summary>
        /// <param name="cullMode">Режим отсечения в локальном формате</param>
        /// <returns>Режим отсечения в формате XNA</returns>
        static public Direct3D9.Cull Convert(CullMode cullMode)
        {
            switch (cullMode)
            {
                case CullMode.Clockwise:
                    return Direct3D9.Cull.Clockwise;
                case CullMode.CounterClockwise:
                    return Direct3D9.Cull.Counterclockwise;
           }
           return Direct3D9.Cull.None;
        }

        /// <summary>
        /// Конвертация режима отсечения полигонов
        /// </summary>
        /// <param name="cullMode">Режим отсечения в формате XNA</param>
        /// <returns>Режим отсечения в локальном формате</returns>
        static public CullMode Convert(Direct3D9.Cull cullMode)
        {
            switch (cullMode)
            {
                case Direct3D9.Cull.Clockwise:
                    return CullMode.Clockwise;
                case Direct3D9.Cull.Counterclockwise:
                    return CullMode.CounterClockwise;
            }
            return CullMode.None;
        }
     
        /// <summary>
        /// Конвертация типов данных представляющих собой вершину
        /// </summary>
        /// <param name="type">Тип здешний</param>
        /// <returns>Тип в XNA</returns>
        static public Direct3D9.DeclarationType Convert(DeclarationType type)
        {
            return (Direct3D9.DeclarationType)type;
        }

        /// <summary>
        /// Конвертация методов декларации вершин
        /// </summary>
        /// <param name="method">Метод декларации здесь</param>
        /// <returns>Метод декларации в SlimDX</returns>
        static public Direct3D9.DeclarationMethod Convert(DeclarationMethod method)
        {
            return (Direct3D9.DeclarationMethod)method;
        }

        /// <summary>
        /// Конвертация режимов предназначения вершинных данных
        /// </summary>
        /// <param name="usage">Предназначение вершинных данных здесь</param>
        /// <returns>Предназначение вершинных данных в SlimDX</returns>
        static public Direct3D9.DeclarationUsage Convert(DeclarationUsage usage)
        {
            return (Direct3D9.DeclarationUsage)usage;
        }

        /// <summary>
        /// Конвертация режимов предназначения вершинных данных
        /// </summary>
        /// <param name="usage">Предназначение вершинных данных в XNA</param>
        /// <returns>Предназначение вершинных данных здесь</returns>
        static public DeclarationUsage Convert(Direct3D9.DeclarationUsage usage)
        {
            return ((DeclarationUsage)usage);
        }
        
        /// <summary>
        /// Конвертация четырёхмерного вектора
        /// </summary>
        /// <param name="vec">Четырехмерный вектор здесь</param>
        /// <returns>Четырехмерный вектор SlimDX</returns>
        static public Slimdx.Vector4 Convert(Vector4 vec)
        {
            return new Slimdx.Vector4((float)vec.X, (float)vec.Y, (float)vec.Z, (float)vec.W);
        }

        /// <summary>
        /// Конвертация четырёхмерного вектора
        /// </summary>
        /// <param name="vec">Четырехмерный вектор SlimDX</param>
        /// <returns>Четырехмерный вектор здесь</returns>
        static public Vector4 Convert(Slimdx.Vector4 vec)
        {
            return new Vector4(vec.X, vec.Y, vec.Z, vec.W);
        }

        /// <summary>
        /// Конвертация трёхмерного вектора
        /// </summary>
        /// <param name="vec">Трехмерный вектор здесь</param>
        /// <returns>Трехмерный вектор SlimDX</returns>
        static public Slimdx.Vector3 Convert(Vector3 vec)
        {
            return new Slimdx.Vector3((float)vec.X, (float)vec.Y, (float)vec.Z);
        }

        /// <summary>
        /// Конвертация трёхмерного вектора
        /// </summary>
        /// <param name="vec">Трехмерный вектор SlimDX</param>
        /// <returns>Трехмерный вектор здесь</returns>
        static public Vector3 Convert(Slimdx.Vector3 vec)
        {
            return new Vector3(vec.X, vec.Y, vec.Z);
        }

        /// <summary>
        /// Конвертация цветов
        /// </summary>
        /// <param name="color">Цвет в SlimDX</param>
        /// <returns>Цвет здешний</returns>
        static public Color Convert(Slimdx.Color4 color)
        {
            Slimdx.Vector4 vector = color.ToVector4();
            return new Color(vector.X, vector.Y, vector.Z, vector.W);
        }

        /// <summary>
        /// Конвертация цветов
        /// </summary>
        /// <param name="color">Цвет здешний</param>
        /// <returns>Цвет в SlimDX</returns>
        static public Slimdx.Vector4 ConvertToVector4(Color color)
        {
            return Convert(color).ToVector4();
        }

        /// <summary>
        /// Конвертация цветов
        /// </summary>
        /// <param name="color">Цвет здешний</param>
        /// <returns>Цвет в SlimDX</returns>
        static public Slimdx.Color4 Convert(Color color)
        {
            return new Slimdx.Color4((float)color.Alpha, (float)color.Red, (float)color.Green, (float)color.Blue);
        }
    }
}
